package com.bluerox.updating;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

/** 
 * 压缩和解压zip文件<br><br>
 * 注意：压缩的文件夹中不能有中文名字,API的中文BUG,但是对于中文内容的文件是不影响的...<br>
 * Example:<br><br>
 * String targetPath = "/home/lijianbo/test/Race/temp/status/";<br>
 * String zipFilePath = "/home/lijianbo/test/Race/temp/status/Race_1_0_0_status.xml.zip";<br>
 * Zip.unzipFile(targetPath, zipFilePath);<br>
 * @author 李建波 ,kiven
 */  
public class Zip {
	private static final int BUFFER = 2048;
	  
	    /** 
	     * 解压zip文件 
	     *  
	     * @param targetPath 解压缩目标路径
	     * @param zipFilePath 待解压缩文件
	     */  
	    public static void unzipFile(String targetPath, String zipFilePath) {  
	  
	        try {  
	            File zipFile = new File(zipFilePath);  
	            InputStream is = new FileInputStream(zipFile);  
	            ZipInputStream zis = new ZipInputStream(is);  
	            ZipEntry entry = null;
	            
	            //循环解压缩所有文件
	            while ((entry = zis.getNextEntry()) != null) {  
	                String zipPath = entry.getName();  
	                try {  
	  
	                	//解压文件夹
	                    if (entry.isDirectory()) {  
	                        File zipFolder = new File(targetPath + File.separator + zipPath);  
	                        if (!zipFolder.exists()) {  
	                            zipFolder.mkdirs();  
	                        }  
	                    } else {  
	                    	//解压文件
	                        File file = new File(targetPath + File.separator + zipPath);  
	                        if (!file.exists()) {  
	                            File pathDir = file.getParentFile();  
	                            pathDir.mkdirs();  
	                            file.createNewFile();  
	                        }  
	  
	                        FileOutputStream fos = new FileOutputStream(file);  
	                        int bread;  
	                        while ((bread = zis.read()) != -1) {  
	                            fos.write(bread);  
	                        }  
	                        fos.close();  
	  
	                    }  
	  
	                } catch (Exception e) {  
	                    continue;  
	                }  
	            }  
	            zis.close();  
	            is.close();  
	        } catch (Exception e) {  
	            e.printStackTrace();  
	        }  
	  
	    }
	    
	    /**
	     * 压缩文件夹  
	     * @param fileName 要压缩文件夹的路径
	     * @param zipFilePath 压缩文件夹后该zip文件所方的路径
	     */
	    public void zip(String fileName,String zipFilePath) {
	    	File file = new File(fileName);
	    	String zipFileName = zipFilePath + File.separator + file.getName() + ".zip";
	    	OutputStream os = null;
	    	ZipOutputStream zos = null;
	    	try {
				os = new FileOutputStream(zipFileName);
				zos = new ZipOutputStream(os);
				doZip(file,zos,"");
				
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			} finally {
				if(zos != null) {
					try {
						zos.close();
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
			}
	    }
	    
	    /**
	     * 压缩文件夹中的所有文件成单独的压缩文件
	     * @param sourcePath	指定要压缩的文件路径
	     * @param zipFilePath	指定压缩文件后所存放该压缩文件的路径
	     */
	    public void zipAllFile(String sourcePath,String zipFilePath) {
	    	File sourceFile = new File(sourcePath);
			File[] files = sourceFile.listFiles();
			
			//遍历该文件夹下的所有文件
			for(File file : files) {
				//如果是文件夹则进行递归遍历
				if(file.isDirectory()) {
					zipAllFile(file.getPath(),zipFilePath);
				}
				//递归所有的文件后还是会回到原来文件的本身，然而这样的情况跟设计的初衷是相违背的，所以此处要加以控制。
				//多加一个条件判断，使得程序满足设计的需要
				if(!file.isDirectory()) {
					//直到找到的是文件,对该文件进行压缩
					//构造压缩文件的名称
					String zipFileName = zipFilePath + File.separator + file.getName() + ".zip";
					OutputStream os = null;
					ZipOutputStream zos = null;
					
					try {
						os = new FileOutputStream(zipFileName);
						zos = new ZipOutputStream(os);
						//压缩文件的方法
						doZip(file,zos);
					} catch (FileNotFoundException e) {
						e.printStackTrace();
					} finally {
						//对文件流操作的时候，最后都必须把流关闭。
						if(zos != null) {
							try {
								zos.close();
							} catch (IOException e) {
								e.printStackTrace();
							}
						}
						if(os != null) {
							try {
								os.close();
							} catch (IOException e) {
								e.printStackTrace();
							}
						}
					}
				}
			}
		}
	    
	    /**
	     * 私有方法，该类内部调用的方法，该法是压缩文件的核心方法，主要处理的是压缩单个文件
	     * @param file  要压缩的文件
	     * @param zos	压缩文件的输出流
	     */
	    private void doZip(File file, ZipOutputStream zos) {
	    	//字节数组，用于缓存作用
			byte[] buf = new byte[BUFFER];
			InputStream is = null;
			BufferedInputStream bs = null;
			//定义zip实体
			ZipEntry entry = null;
			
			try {
				is = new FileInputStream(file);
				bs = new BufferedInputStream(is);
				entry = new ZipEntry(file.getName());
				zos.putNextEntry(entry);
				
				int count = 0;
				//压缩文件
				while((count = bs.read(buf)) != -1) {
					zos.write(buf, 0, count);
				}
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			} finally {
				//关闭流
				if(bs != null) {
					try {
						bs.close();
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
				if(is != null) {
					try {
						is.close();
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
				
			}
	    }
	    
	    /**
	     * 重载doZip方法，这个重载方法主要处理的是压缩整个文件夹的主要功能
	     * @param file 要压缩的文件
	     * @param zos 压缩文件的输出流
	     * @param dir 路径的层次
	     * @throws IOException 
	     */
	    private void doZip(File file,ZipOutputStream zos,String dir) {
	    	if(file.isDirectory()) {
	    		//判断路径的层次，如果是顶层的话就直接获得文件名，如果非顶层就想加一个文件分割符，然后再加上文件名
	    		dir = dir + (dir.length() == 0 ? "":File.separator) + file.getName(); 
	    		File[] files = file.listFiles();
	    		
	    		for(File f : files) {
	    			doZip(f,zos,dir);
	    		}
	    	}
	    	else {
	    		byte[] buf = new byte[BUFFER];
	    		InputStream is = null;
	    		BufferedInputStream bs = null;
	    		ZipEntry entry = null;
	    		dir = dir.length() == 0 ? "":(dir + File.separator + file.getName());
	    		
	    		try {
					is = new FileInputStream(file);
					bs = new BufferedInputStream(is);
					entry = new ZipEntry(dir);
					zos.putNextEntry(entry);
					
					int count;
					while((count = bs.read(buf)) != -1) {
						zos.write(buf, 0, count);
					}
				} catch (FileNotFoundException e) {
					e.printStackTrace();
				} catch (IOException e) {
					e.printStackTrace();
				} finally {
					try {
						if(bs != null) {
							bs.close();
						}
						if (is != null) {
							is.close();
						}
					} catch (IOException e) {
						e.printStackTrace();
					}
					
				}
	    	}
	    }
}
